﻿#version 330 core
precision mediump float;

in vec3 normal_vector;
in vec3 frag_pos; // 片段的位置向量 (世界空间)
in vec2 texture_coord;
out vec4 frag_color;

struct Material {
  sampler2D diffuse; // 漫反射纹理 (环境光照同漫反射)
  sampler2D specular; // 镜面高光纹理 
  float shininess; // 高光反光度
};

// 手电筒
struct Light {
  vec3 position;
  vec3 direction;
  vec3 color;

  vec3 ambient;
  vec3 diffuse;
  vec3 specular;

  float constant;
  float linear;
  float quadratic;
  
  float cut_off;
  float outer_cut_off;
};

uniform vec3 view_pos; // 观察者向量
uniform Material material; // 材质
uniform Light light; // 光源

void main(void) {
  vec3 light_vec = normalize(light.position - frag_pos); // 光线方向 指向物体
  float theta = dot(light_vec, normalize(-light.direction)); // θ 片段指向光源的向量与聚光所指方向向量的夹角
  float epsilon = light.cut_off - light.outer_cut_off; // 余弦值差（ϵ=φ−γ）
  float intensity = clamp((theta - light.outer_cut_off) / epsilon, 0.0f, 1.0f);

  // 环境光照
  vec3 ambient = light.ambient * texture(material.diffuse, texture_coord).rgb * light.color; // 环境分量
  // 漫反射光照
  vec3 norm = normalize(normal_vector);
  float diff = max(dot(norm, light_vec), 0.0f); // 防止夹角大于90度，漫反射分量为负
  vec3 diffuse = light.diffuse * texture(material.diffuse, texture_coord).rgb * diff * light.color; // 漫反射分量 
  // 镜面光照
  vec3 view_vec = normalize(view_pos - frag_pos); // 观察向量
  vec3 reflect_vec = reflect(-light_vec, norm); // 反射要求第一个参数 光线向量的方向是光源指向物体
  float spec = pow(max(dot(view_vec, reflect_vec), 0.0f), material.shininess);
  vec3 specular = light.diffuse * texture(material.specular, texture_coord).rgb * spec * light.color;
  // 点光源光线衰减
  float dist = length(light.position - frag_pos);
  float attenuation = 1.0 / (light.constant + light.linear * dist + light.quadratic * (dist * dist));
  ambient *= attenuation;
  diffuse *= attenuation;
  specular *= attenuation;
  // intensity
  diffuse *= intensity;
  specular *= intensity;
  // 三者混合即为物体反射光 (冯氏光照模型)
  frag_color = vec4(ambient + diffuse + specular, 1.0f);
}